//==============================//
// PROJECT OVERLOAD SOURCE MOD	//
//==============================//
// Butterfly knife

#include "cbase.h"
#include "weapon_hl2mpbasehlmpcombatweapon.h"
#include "weapon_hl2mpbasebasebludgeon.h"
#include "gamerules.h"
#include "ammodef.h"
#include "mathlib/mathlib.h"
#include "in_buttons.h"
#include "vstdlib/random.h"
#include "npcevent.h"

#if defined( CLIENT_DLL )
	#include "c_hl2mp_player.h"
#else
	#include "hl2mp_player.h"
	#include "ai_basenpc.h"
#endif

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

// Weapon defs
#define MELEE_RANGE		75.0f
#define MELEE_REFIRE	0.4f
#define MELEE_DAMAGE	10.0f	// 10 HP ?

#ifdef CLIENT_DLL
	#define CWeaponKnifeButterfly C_WeaponKnifeButterfly
#endif

class CWeaponKnifeButterfly : public CBaseHL2MPBludgeonWeapon
{
public:
	DECLARE_CLASS( CWeaponKnifeButterfly, CBaseHL2MPBludgeonWeapon );
	DECLARE_NETWORKCLASS(); 
	DECLARE_PREDICTABLE();
	#ifndef CLIENT_DLL
		DECLARE_ACTTABLE();
	#endif

	CWeaponKnifeButterfly();
	void	Precache();
	void	Spawn();
	void	Drop( const Vector &vecVelocity );

	float	GetDamageForActivity( Activity hitActivity )	{ return MELEE_DAMAGE; }
	float	GetFireRate( void )								{ return MELEE_REFIRE; }
	float	GetRange( void )								{ return MELEE_RANGE; }

	Activity	GetPrimaryAttackActivity( void )	{	return	ACT_VM_HITCENTER;	}
	Activity	GetSecondaryAttackActivity( void )	{	return	ACT_VM_HITCENTER2;	}
	void		AddViewKick( void );

	// Animation event
	#ifndef CLIENT_DLL
		void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator );
		void HandleAnimEventMeleeHit( animevent_t *pEvent, CBaseCombatCharacter *pOperator );
		int WeaponMeleeAttack1Condition( float flDot, float flDist ); 
	#endif

	CWeaponKnifeButterfly( const CWeaponKnifeButterfly & );
};


IMPLEMENT_NETWORKCLASS_ALIASED( WeaponKnifeButterfly, DT_WeaponKnifeButterfly )
	BEGIN_NETWORK_TABLE( CWeaponKnifeButterfly, DT_WeaponKnifeButterfly )
END_NETWORK_TABLE()

BEGIN_PREDICTION_DATA( CWeaponKnifeButterfly )
END_PREDICTION_DATA()

LINK_ENTITY_TO_CLASS( weapon_knife_butterfly, CWeaponKnifeButterfly );
PRECACHE_WEAPON_REGISTER( weapon_knife_butterfly );


#ifndef CLIENT_DLL
	acttable_t	CWeaponKnifeButterfly::m_acttable[] = 
	{
		{ ACT_MP_STAND_IDLE,				ACT_HL2MP_IDLE_MELEE,					false },
		{ ACT_MP_CROUCH_IDLE,				ACT_HL2MP_IDLE_CROUCH_MELEE,			false },

		{ ACT_MP_RUN,						ACT_HL2MP_RUN_MELEE,					false },
		{ ACT_MP_CROUCHWALK,				ACT_HL2MP_WALK_CROUCH_MELEE,			false },

		{ ACT_MP_ATTACK_STAND_PRIMARYFIRE,	ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE,	false },
		{ ACT_MP_ATTACK_CROUCH_PRIMARYFIRE,	ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE,	false },

		{ ACT_MP_RELOAD_STAND,				ACT_HL2MP_GESTURE_RELOAD_MELEE,			false },
		{ ACT_MP_RELOAD_CROUCH,				ACT_HL2MP_GESTURE_RELOAD_MELEE,			false },

		{ ACT_MP_JUMP,						ACT_HL2MP_JUMP_MELEE,					false },	
	//#ifdef SecobMod__Enable_Fixed_Multiplayer_AI	
		{ ACT_HL2MP_IDLE,					ACT_HL2MP_IDLE_MELEE,					false },
		{ ACT_HL2MP_RUN,					ACT_HL2MP_RUN_MELEE,					false },
		{ ACT_HL2MP_IDLE_CROUCH,			ACT_HL2MP_IDLE_CROUCH_MELEE,			false },
		{ ACT_HL2MP_WALK_CROUCH,			ACT_HL2MP_WALK_CROUCH_MELEE,			false },
		{ ACT_HL2MP_GESTURE_RANGE_ATTACK,	ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE,	false },
		{ ACT_HL2MP_GESTURE_RELOAD,			ACT_HL2MP_GESTURE_RELOAD_MELEE,		false },
		{ ACT_HL2MP_JUMP,					ACT_HL2MP_JUMP_MELEE,					false },
	

		{ ACT_MELEE_ATTACK1,	ACT_MELEE_ATTACK_SWING, true }, 
		{ ACT_IDLE,				ACT_IDLE_ANGRY_MELEE,	false }, 
		{ ACT_IDLE_ANGRY,		ACT_IDLE_ANGRY_MELEE,	false }, 
	//#endif //SecobMod__Enable_Fixed_Multiplayer_AI
	};

	IMPLEMENT_ACTTABLE(CWeaponKnifeButterfly);
#endif

//=============
// Constructor
//=============
CWeaponKnifeButterfly::CWeaponKnifeButterfly( void )
{
	// Duh
}

//==========
// Precache
//==========
void CWeaponKnifeButterfly::Precache()
{
	BaseClass::Precache();
}

//==========
// Spawn
//==========
void CWeaponKnifeButterfly::Spawn()
{
	Precache();
	BaseClass::Spawn();
}



// bool	Deploy( void )
// bool	Holster( CBaseCombatWeapon *pSwitchingTo = NULL );

void CWeaponKnifeButterfly::Drop( const Vector &vecVelocity )
{
#ifndef CLIENT_DLL
	UTIL_Remove( this );
#endif
}


void CWeaponKnifeButterfly::AddViewKick( void )
{
	CBasePlayer *pPlayer  = ToBasePlayer( GetOwner() );
	
	if ( pPlayer == NULL )
		return;

	QAngle punchAng;

	punchAng.x = SharedRandomFloat( "knifepax", 1.0f, 2.0f );
	punchAng.y = SharedRandomFloat( "knifepay", -2.0f, -1.0f );
	punchAng.z = 0.0f;
	
	pPlayer->ViewPunch( punchAng ); 
}


#ifndef CLIENT_DLL

//-----------------------------------------------------------------------------
// Animation event handlers
//-----------------------------------------------------------------------------
void CWeaponKnifeButterfly::HandleAnimEventMeleeHit( animevent_t *pEvent, CBaseCombatCharacter *pOperator )
{
	// Trace up or down based on where the enemy is...
	// But only if we're basically facing that direction
	Vector vecDirection;
	AngleVectors( GetAbsAngles(), &vecDirection );

#ifdef SecobMod__Enable_Fixed_Multiplayer_AI
	CBaseEntity *pEnemy = pOperator->MyNPCPointer() ? pOperator->MyNPCPointer()->GetEnemy() : NULL;
	if ( pEnemy )
	{
		Vector vecDelta;
		VectorSubtract( pEnemy->WorldSpaceCenter(), pOperator->Weapon_ShootPosition(), vecDelta );
		VectorNormalize( vecDelta );
		
		Vector2D vecDelta2D = vecDelta.AsVector2D();
		Vector2DNormalize( vecDelta2D );
		if ( DotProduct2D( vecDelta2D, vecDirection.AsVector2D() ) > 0.8f )
		{
			vecDirection = vecDelta;
		}
	}
#endif //SecobMod__Enable_Fixed_Multiplayer_AI

	Vector vecEnd;
	VectorMA( pOperator->Weapon_ShootPosition(), 50, vecDirection, vecEnd );
	CBaseEntity *pHurt = pOperator->CheckTraceHullAttack( pOperator->Weapon_ShootPosition(), vecEnd, 
		Vector(-16,-16,-16), Vector(36,36,36), GetDamageForActivity( GetActivity() ), DMG_CLUB, 0.75 );
	
	// did I hit someone?
	if ( pHurt )
	{
		// play sound
		WeaponSound( MELEE_HIT );

		// Fake a trace impact, so the effects work out like a player's crowbaw
		trace_t traceHit;
		UTIL_TraceLine( pOperator->Weapon_ShootPosition(), pHurt->GetAbsOrigin(), MASK_SHOT_HULL, pOperator, COLLISION_GROUP_NONE, &traceHit );
		ImpactEffect( traceHit );
	}
	else
	{
		WeaponSound( MELEE_MISS );
	}
}


//-----------------------------------------------------------------------------
// Animation event
//-----------------------------------------------------------------------------
void CWeaponKnifeButterfly::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator )
{
	switch( pEvent->event )
	{
	case EVENT_WEAPON_MELEE_HIT:
		HandleAnimEventMeleeHit( pEvent, pOperator );
		break;

	default:
		BaseClass::Operator_HandleAnimEvent( pEvent, pOperator );
		break;
	}
}

//-----------------------------------------------------------------------------------
// Attempt to lead the target (needed because citizens can't hit manhacks with melee)
// Fograin92: Let's leave it here for now
//-----------------------------------------------------------------------------------
int CWeaponKnifeButterfly::WeaponMeleeAttack1Condition( float flDot, float flDist )
{
	// Attempt to lead the target
	CAI_BaseNPC *pNPC	= GetOwner()->MyNPCPointer();
	CBaseEntity *pEnemy = pNPC->GetEnemy();
	if (!pEnemy)
		return COND_NONE;

	Vector vecVelocity;
	vecVelocity = pEnemy->GetSmoothedVelocity( );

	// Project where the enemy will be in a little while
	float dt = 0.9;
	dt += SharedRandomFloat( "knifemelee1", -0.3f, 0.2f );
	if ( dt < 0.0f )
		dt = 0.0f;

	Vector vecExtrapolatedPos;
	VectorMA( pEnemy->WorldSpaceCenter(), dt, vecVelocity, vecExtrapolatedPos );

	Vector vecDelta;
	VectorSubtract( vecExtrapolatedPos, pNPC->WorldSpaceCenter(), vecDelta );

	if ( fabs( vecDelta.z ) > 70 )
	{
		return COND_TOO_FAR_TO_ATTACK;
	}

	Vector vecForward = pNPC->BodyDirection2D( );
	vecDelta.z = 0.0f;
	float flExtrapolatedDist = Vector2DNormalize( vecDelta.AsVector2D() );
	if ((flDist > 64) && (flExtrapolatedDist > 64))
	{
		return COND_TOO_FAR_TO_ATTACK;
	}

	float flExtrapolatedDot = DotProduct2D( vecDelta.AsVector2D(), vecForward.AsVector2D() );
	if ((flDot < 0.7) && (flExtrapolatedDot < 0.7))
	{
		return COND_NOT_FACING_ATTACK;
	}

	return COND_CAN_MELEE_ATTACK1;
}

#endif
